use anyhow::{Context, Result};
use futures_util::StreamExt;
use indicatif::{ProgressBar, ProgressStyle};
use reqwest::Client;
use std::path::{Path, PathBuf};
use std::time::Duration;
use tokio::fs::{self, File};
use tokio::io::AsyncWriteExt;
use tokio::time;
use walkdir::WalkDir;
use crate::gpg;

pub async fn run_mirror_task(
    config: crate::config::Config,
    storage: crate::storage::Storage,
) {
    let client = Client::new();
    let mut interval = time::interval(Duration::from_secs(config.mirror.sync_interval));
    
    loop {
        interval.tick().await;
        
        log::info!("开始同步镜像...");
        if let Err(e) = mirror_distributions(&config, &storage, &client).await {
            log::error!("镜像同步失败: {}", e);
        } else {
            log::info!("镜像同步完成");
        }
    }
}

async fn mirror_distributions(
    config: &crate::config::Config,
    storage: &crate::storage::Storage,
    client: &Client,
) -> Result<()> {
    for dist in &config.mirror.distributions {
        for arch in &config.mirror.architectures {
            if let Err(e) = mirror_distribution_arch(config, storage, client, dist, arch).await {
                log::error!("同步 {}/{} 失败: {}", dist, arch, e);
            } else {
                log::info!("成功同步 {}/{}", dist, arch);
            }
        }
    }
    Ok(())
}

async fn mirror_distribution_arch(
    config: &crate::config::Config,
    storage: &crate::storage::Storage,
    client: &Client,
    distribution: &str,
    architecture: &str,
) -> Result<()> {
    // 1. 下载 Packages 文件
    let packages_url = format!(
        "{}/dists/{}/main/binary-{}/Packages",
        config.mirror.upstream_url, distribution, architecture
    );
    
    log::debug!("下载 Packages 文件: {}", packages_url);
    let packages_content = client
        .get(&packages_url)
        .send()
        .await?
        .text()
        .await?;
    
    // 2. 解析 Packages 文件，获取所有软件包
    let packages = parse_packages_file(&packages_content)?;
    log::info!("发现 {} 个软件包 ({} 架构)", packages.len(), architecture);
    
    // 3. 下载并处理每个软件包
    let pb = ProgressBar::new(packages.len() as u64);
    pb.set_style(ProgressStyle::default_bar()
        .template("{spinner:.green} [{elapsed_precise}] [{bar:40.cyan/blue}] {pos}/{len} ({eta})")
        .unwrap()
        .progress_chars("#>-"));
    
    for package in packages {
        pb.set_message(&format!("下载: {}", package.name));
        
        if storage.file_exists(&package.path).await {
            pb.inc(1);
            continue;
        }
        
        let package_url = format!("{}/{}", config.mirror.upstream_url, package.path);
        let dest_path = storage.root_path().join(&package.path);
        
        if let Some(parent) = dest_path.parent() {
            fs::create_dir_all(parent).await?;
        }
        
        download_package(client, &package_url, &dest_path).await?;
        pb.inc(1);
    }
    
    pb.finish_with_message("下载完成");
    
    // 4. 生成 Release 文件并签名
    generate_release_file(config, storage, distribution, architecture).await?;
    
    Ok(())
}

fn parse_packages_file(content: &str) -> Result<Vec<PackageInfo>> {
    let mut packages = Vec::new();
    let mut current_package = PackageInfo::default();
    
    for line in content.lines() {
        if line.is_empty() {
            if !current_package.path.is_empty() {
                packages.push(current_package);
                current_package = PackageInfo::default();
            }
            continue;
        }
        
        if let Some((key, value)) = line.split_once(':') {
            match key.trim() {
                "Filename" => current_package.path = value.trim().to_string(),
                "SHA256" => current_package.sha256 = value.trim().to_string(),
                "Package" => current_package.name = value.trim().to_string(),
                "Version" => current_package.version = value.trim().to_string(),
                _ => {}
            }
        }
    }
    
    if !current_package.path.is_empty() {
        packages.push(current_package);
    }
    
    Ok(packages)
}

async fn download_package(
    client: &Client,
    url: &str,
    dest_path: &Path,
) -> Result<()> {
    let mut response = client.get(url).send().await?;
    let mut file = File::create(dest_path).await?;
    
    while let Some(chunk) = response.chunk().await? {
        file.write_all(&chunk).await?;
    }
    file.flush().await?;
    
    Ok(())
}

async fn generate_release_file(
    config: &crate::config::Config,
    storage: &crate::storage::Storage,
    distribution: &str,
    architecture: &str,
) -> Result<()> {
    let release_path = storage.root_path().join(format!(
        "dists/{}/main/binary-{}/Release",
        distribution, architecture
    ));
    
    if let Some(parent) = release_path.parent() {
        fs::create_dir_all(parent).await?;
    }
    
    let mut release_content = format!(
        "Origin: Termux Mirror\n\
        Label: Termux\n\
        Suite: {}\n\
        Codename: {}\n\
        Architectures: {}\n\
        Components: main\n\
        Description: Termux 软件包镜像\n",
        distribution, distribution, architecture
    );
    
    // 添加文件哈希
    release_content.push_str("\n");
    
    // 遍历所有文件并计算哈希
    let base_path = storage.root_path().join(format!(
        "dists/{}/main/binary-{}",
        distribution, architecture
    ));
    
    let mut files = Vec::new();
    
    for entry in WalkDir::new(&base_path) {
        let entry = entry?;
        if entry.file_type().is_file() {
            files.push(entry.path().to_path_buf());
        }
    }
    
    let pb = ProgressBar::new(files.len() as u64);
    pb.set_style(ProgressStyle::default_bar()
        .template("{spinner:.green} [{elapsed_precise}] 计算文件哈希 {bar:40.cyan/blue} {pos}/{len}")
        .unwrap()
        .progress_chars("#>-"));
    
    for file_path in files {
        let relative_path = file_path.strip_prefix(&storage.root_path())?;
        
        let data = fs::read(&file_path).await?;
        let sha256 = sha2::Sha256::digest(&data);
        let sha256_hex = hex::encode(sha256);
        
        release_content.push_str(&format!(
            " {} {} {}\n",
            sha256_hex,
            data.len(),
            relative_path.display()
        ));
        
        pb.inc(1);
    }
    
    pb.finish_with_message("文件哈希计算完成");
    
    fs::write(&release_path, &release_content).await?;
    
    // 签名 Release 文件
    log::info!("签名 Release 文件...");
    let signature = gpg::sign_release_file(&release_path).await?;
    let sig_path = release_path.with_extension("gpg");
    fs::write(sig_path, signature).await?;
    
    Ok(())
}

#[derive(Default, Debug)]
struct PackageInfo {
    name: String,
    version: String,
    path: String,
    sha256: String,
}